home *** CD-ROM | disk | FTP | other *** search
- /*-------------------------------------------------------------------
-
- AOCE Post Office Protocol (POP) / Simple Mail Transfer Protocol (SMTP)
- Mail Service Access Module
-
- written by Steve Falkenburg-- MacDTS
- ©1991-1993 Apple Computer, Inc.
-
- --------------
- change history
- --------------
-
- SJF 02/19/93 update for beta build b1
- SJF 10/29/92 update to a11 a11
- SJF 06/08/92 update to a8 a8
- SJF 02/15/92 first working version a4.5
- SJF 10/16/91 initial coding a3
-
- ---------------------------------------------------------------------*/
-
- #include <ctype.h>
- #include <string.h>
-
- #include "const.h"
- #include "gwerrors.h"
- #include "mytypes.h"
- #include "globals.h"
- #include "utils.h"
- #include "parser.h"
- #include "network.h"
- #include "spoolsystem.h"
- #include "smtp.protocol.h"
-
- /* This call takes a FULLY FORMED RFC-822 format message as input, and sends the message
- using SMTP to the specified host
-
- the text is sent in "text" in the form of a zero-terminated C string
- the sender is specified in "fromAddress"
- the SMTP server is specified in "smtpServerAddress"
- */
-
- OSErr SendSMTP(char *headerText,FSSpec *rawTextContent,char *bccText,char *fromAddress,unsigned long smtpServerAddress)
- {
- unsigned long stream;
- Ptr response;
- unsigned long responseLength,contentChunkLen,blockOffset;
- OSErr err,err2;
- char *command,*contentChunk;
- char *lfText;
-
- TCP_FlushBytes(); // flush out old TCP response data
-
- command = nil;
- stream = 0L;
-
- err = AddLF(headerText,&lfText); // add linefeeds to message
- if (err!=noErr) {
- ExitSMTP(stream,nil,command);
- return err;
- }
-
- command = (char *)NewPtrChk(kSMTPCommandLength);
- if (MemError()!=noErr) {
- return MemError();
- }
-
- err = TCP_CreateStream(&stream);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
-
- err = TCP_ActiveOpen(stream,smtpServerAddress,kSMTPPort,kSMTPTimeout);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return kInvalidSMTPServer;
- }
-
- /* get introduction message */
-
- err = SMTP_GetResponse(stream,&response,&responseLength);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
- else if (!PositiveResponse(response)) {
- DisposPtrChk(response);
- ExitSMTP(stream,lfText,command);
- return kSMTPError;
- }
- DisposPtrChk(response);
-
- /* send "HELO" message */
-
- strcpy(command,"HELO [");
- strcat(command,gOurIPString);
- strcat(command,"]");
- err = SMTP_Command(stream,command,&response,&responseLength);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
- else if (!PositiveResponse(response)) {
- DisposPtrChk(response);
- ExitSMTP(stream,lfText,command);
- return kSMTPError;
- }
- DisposPtrChk(response);
-
- /* specify sender with MAIL FROM:<> field */
-
- strcpy(command,"MAIL FROM:<");
- strcat(command,fromAddress);
- strcat(command,">");
- err = SMTP_Command(stream,command,&response,&responseLength);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
- else if (!PositiveResponse(response)) {
- DisposPtrChk(response);
- ExitSMTP(stream,lfText,command);
- return kSMTPError;
- }
- DisposPtrChk(response);
-
- /* add message recipients in RCPT TO:<> field */
-
- err = RcptMsg(lfText,stream,"To:");
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
- err = RcptMsg(lfText,stream,"Cc:");
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
- err = RcptMsg(bccText,stream,"Bcc:");
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
-
- /* send DATA command */
-
- err = SMTP_Command(stream,"DATA",&response,&responseLength);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
- else if (!PositiveResponse(response)) {
- DisposPtrChk(response);
- ExitSMTP(stream,lfText,command);
- return kSMTPError;
- }
- DisposPtrChk(response);
-
- /* send message header */
-
- err = TCP_Send(stream,lfText,(unsigned short)strlen(lfText),true,kSMTPTimeout);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
-
- /* send message contents (as one raw block, in chunks) */
-
- contentChunk = (char *)NewPtrChk(kMaxBufferSize);
- if (MemError()!=noErr) {
- DisposPtrChk(response);
- ExitSMTP(stream,lfText,command);
- return MemError();
- }
- blockOffset = 0;
- do {
- contentChunkLen = kMaxBufferSize;
- err = GetFromSpool(rawTextContent,kRawContentType,kRawContentCreator,0,contentChunk,&contentChunkLen,blockOffset);
- if ((err==noErr)||(err==kMoreData)) {
- err2 = TCP_Send(stream,contentChunk,(unsigned short)contentChunkLen,true,kSMTPTimeout);
- blockOffset += contentChunkLen;
- }
- }
- while ((err2==noErr) && (err==kMoreData));
- DisposPtrChk(contentChunk);
- if (err2!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err2;
- }
-
- /* send message terminator */
-
- err = SMTP_Command(stream,kMessageTerminator,&response,&responseLength);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
- else if (!PositiveResponse(response)) {
- DisposPtrChk(response);
- ExitSMTP(stream,lfText,command);
- return kSMTPError;
- }
- DisposPtrChk(response);
-
- /* send QUIT to terminate session */
-
- err = SMTP_Command(stream,"QUIT",&response,&responseLength);
- if (err!=noErr) {
- ExitSMTP(stream,lfText,command);
- return err;
- }
- else if (!PositiveResponse(response)) {
- DisposPtrChk(response);
- ExitSMTP(stream,lfText,command);
- return kSMTPError;
- }
- DisposPtrChk(response);
-
- ExitSMTP(stream,lfText,command);
- return err;
- }
-
-
- void ExitSMTP(unsigned long stream,Ptr lfText,char *command)
- {
- if (lfText)
- DisposPtrChk(lfText);
-
- if (command) {
- DisposPtrChk(command);
- TCP_CloseConnection(stream,kSMTPTimeout);
- TCP_ReleaseStream(stream);
- }
- }
-
-
-
- /* RcptMsg determines the recipients of the message and sends commands
- to the SMTP server specifying these people as recipients.
- */
-
- OSErr RcptMsg(char *text,unsigned long stream,char *header)
- {
- OSErr err;
- char *command;
- Ptr response;
- unsigned long responseLength;
- char recipient[256];
- char *endOfHeader,*lineEnd,*curLine,*tmpWord;
-
- endOfHeader = strstr(text,kHeaderTerminator);
- if (!endOfHeader)
- return noErr;
-
- command = (char *)NewPtrChk(kSMTPCommandLength);
- if (MemError()!=noErr) {
- return MemError();
- }
-
- lineEnd = text;
- while (lineEnd < endOfHeader) {
- GetLine(&curLine,&lineEnd);
- if (strstr(curLine,header)==curLine) {
- GetWord(&tmpWord,&curLine);
- while (*curLine && curLine<lineEnd) {
- GetWord(&tmpWord,&curLine);
- if (curLine<=lineEnd) {
- CopyWord(recipient,tmpWord);
-
- /* add recipient */
- strcpy(command,"RCPT TO:<");
- strcat(command,recipient);
- strcat(command,">");
- err = SMTP_Command(stream,command,&response,&responseLength);
- if (err!=noErr && !PositiveResponse(response)) {
- DisposPtrChk(command);
- return err;
- }
- DisposPtrChk(response);
-
- }
- }
- }
- }
-
- DisposPtrChk(command);
- return err;
- }
-
-
- OSErr SMTP_Command(unsigned long connID,char *command,Ptr *response,unsigned long *responseLength)
- {
- Ptr sendCommand;
- unsigned short sendLength;
- OSErr err;
-
- sendLength = strlen(command)+2;
- sendCommand = NewPtrChk((long)sendLength+1);
- if (MemError()!=noErr)
- return MemError();
-
- strcpy(sendCommand,command);
- strcat(sendCommand,kCRLF);
-
- err = TCP_Send(connID,sendCommand,sendLength,true,kSMTPTimeout);
- if (err!=noErr) {
- DisposPtrChk(sendCommand);
- return err;
- }
-
- err = SMTP_GetResponse(connID,response,responseLength);
- DisposPtrChk(sendCommand);
- return err;
- }
-
-
- OSErr SMTP_GetResponse(unsigned long connID,Ptr *response,unsigned long *responseLength)
- {
- OSErr err;
- Boolean inMultiLine;
- unsigned short bytesReceived,bytesLeft,lineBytesReceived;
- Ptr responseBuffer,lineStartPtr;
- unsigned char netByte;
- char extenderString[5];
-
- *response = nil;
- inMultiLine = false;
- bytesReceived = 0;
- bytesLeft = kSMTPCommandLength-1;
- lineBytesReceived = 0;
-
- *response = responseBuffer = NewPtrChk(kSMTPCommandLength);
- if (MemError()!=noErr)
- return MemError();
- *responseBuffer = '\0';
-
- do {
- lineStartPtr = responseBuffer;
- do {
- err = TCP_ReadByte(connID,&netByte,kSMTPTimeout);
- if (err==noErr) {
- *responseBuffer++ = netByte;
- *responseBuffer = '\0';
- bytesReceived++;
- bytesLeft--;
- }
- } while (err==noErr && bytesLeft>0 && netByte!=LF);
- inMultiLine = CheckExtendedReply(inMultiLine,lineStartPtr,responseBuffer,extenderString);
- } while (inMultiLine);
-
- *responseLength = bytesReceived;
-
- return err;
- }
-
-
- Boolean CheckExtendedReply(Boolean inExtendedReply,Ptr lineStart,Ptr curPtr,char *extenderString)
- {
- if ((curPtr-lineStart) < 4)
- return false;
-
- if (!inExtendedReply && lineStart[3]==kExtenderChar) {
- if (isdigit(lineStart[0]) && isdigit(lineStart[1]) && isdigit(lineStart[2])) {
- BlockMove(lineStart,extenderString,3);
- extenderString[3] = ' ';
- extenderString[4] = '\0';
- return true;
- }
- }
-
- if (inExtendedReply && strncmp(lineStart,extenderString,4)==0)
- return false;
-
- return inExtendedReply;
- }
-
-
- Boolean PositiveResponse(char *response)
- {
- if (*response > '3')
- return false;
-
- return true;
- }
-